﻿using System.Collections.Generic;
using System;
using System.Linq;

namespace Microsoft.WowAddonStudio.TocEditor
{
	/// <summary>
	/// Manages metadata part of TOC document.
	/// </summary>
    public class MetadataManager : IMetadataManager
    {
        #region Private members

        private readonly TocMetadata metadata;

        #endregion

        #region Lifecycle methods

		/// <summary>
		/// Initializes a new instance of the <see cref="MetadataManager"/> class.
		/// </summary>
		/// <param name="document">The document.</param>
        public MetadataManager(TocDocument document)
        {
        	if (document == null) 
				throw new ArgumentNullException("document");

        	if (document.Tags == null)
                throw new ArgumentNullException("tags");

            this.metadata = document.Tags;
			document.DocumentFileChanged += document_DocumentFileChanged;
        }

		/// <summary>
		/// Handles the DocumentFileChanged event of the document control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void document_DocumentFileChanged(object sender, EventArgs e)
		{
			foreach (var commonTagName in TocTagName.GetCommonTagNames())
			{
				//Raise basic events...
				RaiseOnMetadataChangedEvent(commonTagName, TagType.BASIC);
			}

			//Raise extended event...
			RaiseOnMetadataChangedEvent(TocTagName.XEmail, TagType.EXTENDED);
		}

        #endregion

        #region IMetadataManager Members
		/// <summary>
		/// The event is raised when the managed metadata is changed.
		/// </summary>
		public event EventHandler<MetadataManagerEventArgs> OnMetadataChanged;

		/// <summary>
		/// Sets the given tag name to a given value.
		/// </summary>
		/// <param name="name">Name of metadata tag to be set.</param>
		public string this[string name]
        {
            set
            {
				if(IsBasicTagName(name) && string.IsNullOrEmpty(value))
				{
					if(metadata.ContainsKey(name))
					{
						metadata.Remove(name);
						RaiseOnMetadataChangedEvent(name, IsBasicTagName(name) ? TagType.BASIC : TagType.EXTENDED);	
					}
				}
				else if (!metadata.ContainsKey(name) || metadata[name] != value)
				{
					metadata[name] = value;
					RaiseOnMetadataChangedEvent(name, IsBasicTagName(name) ? TagType.BASIC : TagType.EXTENDED);
				}
            }
        }

		/// <summary>
		/// Removes the tag with the given name from the collection.
		/// </summary>
		/// <param name="tagName">Name of tag to be removed.</param>
		public void Remove(string tagName)
		{
			metadata.Remove(tagName);
			RaiseOnMetadataChangedEvent(tagName, IsBasicTagName(tagName) ? TagType.BASIC : TagType.EXTENDED);
		}

		/// <summary>
		/// Gets basic metadata (title, author, version, interface, notes).
		/// </summary>
		public IEnumerable<KeyValuePair<string, string>> GetBasicTags()
        {
            return metadata.GetTags().Where(kvp => IsBasicTagName(kvp.Key));
        }

		/// <summary>
		/// Gets other metadata specified by user.
		/// </summary>
		public IEnumerable<KeyValuePair<string, string>> GetExtendedTags()
        {
            return metadata.GetTags().Where(kvp => !IsBasicTagName(kvp.Key));
        }
        #endregion

        #region Private member functions

		/// <summary>
		/// Raises the on metadata changed event.
		/// </summary>
		/// <param name="affectedEntry">The affected entry.</param>
		/// <param name="tagType">Type of the tag.</param>
        private void RaiseOnMetadataChangedEvent(string affectedEntry, TagType tagType)
        {
            if(OnMetadataChanged!=null)
            {
                switch (tagType)
                {
                    case TagType.BASIC:
                        OnMetadataChanged(this, new MetadataManagerEventArgs(this, GetBasicTags(), affectedEntry,
                            tagType));
                        break;
                    case TagType.EXTENDED:
                        OnMetadataChanged(this, new MetadataManagerEventArgs(this, GetExtendedTags(), affectedEntry,
                            tagType));
                        break;
                    default:
                        break;
                }
            }               
        }

		/// <summary>
		/// Determines whether [is basic tag name] [the specified name].
		/// </summary>
		/// <param name="name">The name.</param>
		/// <returns>
		/// 	<c>true</c> if [is basic tag name] [the specified name]; otherwise, <c>false</c>.
		/// </returns>
        private static bool IsBasicTagName(string name)
        {
            return name == TocTagName.Title || name == TocTagName.Author || name == TocTagName.Version ||
                   name == TocTagName.Interface || name == TocTagName.Notes;
        }

        #endregion
	}
}